@Singleton @Alternative public class MobileView implements View { // ... // }
It may be desirable to have multiple matching dependencies for a given injection point with the ability to specify which implementation to use at runtime. For instance, you may have different versions of your application which target different browsers or capabilities of the browser. Using alternatives allows you to share common interfaces among your beans, while still using dependency injection, by exporting consideration of what implementation to use to the container's configuration.
Consider the following example:
@Singleton @Alternative public class MobileView implements View { // ... // }
and
@Singleton @Alternative public class DesktopView implements View { // ... //
In our controller logic we in turn inject the View interface:
@EntryPoint public class MyApp { @Inject View view; // ... // }
This code is unaware of the implementation of View, which maintains good separation of concerns. However, this of course creates an ambiguous dependency on the View interface as it has two matching subtypes in this case. Thus, we must configure the container to specify which alternative to use. Also note, that the beans in both cases have been annotated with javax.enterprise.inject.Alternative.
In your ErraiApp.properties for the module, you can simply specify which active alternative should be used:
errai.ioc.enabled.alternatives=org.foo.MobileView
You can specify multiple alternative classes by white space separating them:
errai.ioc.enabled.alternatives=org.foo.MobileView \ org.foo.HTML5Orientation \ org.foo.MobileStorage
You can only have one enabled alternative for a matching set of alternatives, otherwise you will get ambiguous resolution errors from the container.
Similar to alternatives, but specifically designed for testing scenarios, you can replace beans with mocks at runtime for the purposes of running unit tests. This is accomplished simply by annotating a bean with the org.jboss.errai.ioc.client.api.TestMock annotation. Doing so will prioritize consideration of the bean over any other matching beans while running unit tests.
Consider the following:
@ApplicationScoped public class UserManagementImpl implements UserManagement { public List<User> listUsers() { // do user listy things! } }
You can specify a mock implementation of this class by implementing its common parent type (UserManagement) and annotating that class with the @TestMock annotation inside your test package like so:
@TestMock @ApplicationScoped public class MockUserManagementImpl implements UserManagement { public List<User> listUsers() { // return only a test user. return Collections.singletonList(TestUser.INSTANCE); } }
In this case, the container will replace the UserManagementImpl with the MockUserManagementImpl automatically when running the unit tests.
The @TestMock annotation can also be used to specify alternative providers during test execution. For example, it can be used to mock a Caller<T>. Callers are used to invoke RPC or JAX-RS endpoints. During tests you might want to replace theses callers with mock implementations. For details on providers see Container Wiring.
@TestMock @IOCProvider public class MockedHappyServiceCallerProvider implements ContextualTypeProvider<Caller<HappyService>> { @Override public Caller<HappyService> provide(Class<?>[] typeargs, Annotation[] qualifiers) { return new Caller<HappyService>() { ... } }